package gui.Main;

import gui.GUIFacade;
import gui.mapper.NodeListing;

import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.ServerSocket;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;

import phase6.GlobalObjectId;
import phase6.ObjectDB;
import phase6.PeerCommunicator;
import phase6.PortNumber;
import cs340.stormtroopers.hypeerweb.HyPeerWeb;
import cs340.stormtroopers.hypeerweb.HyPeerWebProxy;

/**
 * The central GUI used to display information about the HyPeerWeb and debug
 * information
 * 
 * @author Matthew Smith
 * 
 */
public class GUI extends JFrame
{
	private static GUI singleton = null;
	private static final String DATABASE_NAME = "cs340phase5database.sqlite";
	public static final int GUI_PORT = 49200;

	/** Main Debugger Panel **/
	private HyPeerWebDebugger debugger;

	private HyPeerWeb hypeerweb;
	private JScrollPane scrollPane;

	/**
	 * Creates and initializes the GUI as being the root
	 */
	public GUI(HyPeerWeb hypeerweb)
	{
		this.hypeerweb = hypeerweb;

		this.setTitle("HyPeerWeb DEBUGGER V 1.1");

		this.addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent we)
			{
				shutdown();
				System.exit(0);
			}
		});

		debugger = new HyPeerWebDebugger(this);
		scrollPane = new JScrollPane(debugger);
		scrollPane.setPreferredSize(new Dimension(debugger.WIDTH + 20,
				debugger.HEIGHT));

		this.getContentPane().add(scrollPane);

		this.pack();

	}

	public GUI()
	{
		// used by GUIProxy DO NOT REMOVE
	}

	public void shutdown()
	{
		//hypeerweb.close();
		hypeerweb.removeGUI(GUIFacade.getSingleton(this));
	}

	public static GUI getSingleton(HyPeerWeb hypeerweb)
	{
		if (singleton == null)
		{
			try
			{
				singleton = new GUI(hypeerweb);

				singleton.setVisible(true);
			}
			catch (Exception e)
			{
				JOptionPane
						.showMessageDialog(
								null,
								"Error occurred while attempting to create GUI singleton\nIf you're seeing this while the GUI is running, something is probably seriously wrong\nderp",
								"ERROR", JOptionPane.ERROR_MESSAGE);
				e.printStackTrace();
				hypeerweb.close();
				System.exit(1);
			}
		}
		return singleton;
	}

	/**
	 * Start Point of the Program
	 */
	public static void main(String[] args)
	{
		//automatically find a working port
		int portNum = 0;
		try
		{
			ServerSocket sock = new ServerSocket(0);
			portNum = sock.getLocalPort();
			sock.close();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		
		// initialize network communication
		PortNumber port = new PortNumber(portNum);
		PortNumber.setApplicationsPortNumber(port);
		PeerCommunicator.createPeerCommunicator(port);
		
		// initialize a hypeerweb to start up with
		HyPeerWeb hw = HyPeerWeb.getSingleton();
		hw.reload(DATABASE_NAME);
		
		// initialize the GUI and its facade
		GUI g = getSingleton(hw);
		GUIFacade facade = GUIFacade.getSingleton(g);
		ObjectDB.getSingleton().store(facade.getLocalId(), facade);
		
		hw.addGUI(facade);
	}

	/**
	 * Retrieves the HyPeerWeb Debugging Panel
	 * 
	 * @return HyPeerWebDebugger
	 */
	public HyPeerWebDebugger getHyPeerWebDebugger()
	{
		return debugger;
	}

	public HyPeerWeb getHyPeerWeb()
	{
		return hypeerweb;
	}

	public void finalize()
	{
		// by now it's too late to do anything because the socket will be closed
		//hypeerweb.close();
		//hypeerweb.removeGUI(GUIFacade.getSingleton(this));
	}

	private void setHyPeerWeb(HyPeerWeb newHw)
	{
		hypeerweb = newHw;
		NodeListing nl = debugger.getMapper().getNodeListing();
		nl.clearList();
		nl.initList();
	}

	public void joinSession(String addr, PortNumber port)
	{
		GUIFacade facade = GUIFacade.getSingleton(this);
		hypeerweb.removeGUI(facade);
		
		GlobalObjectId hwID = new GlobalObjectId(addr, port,
				HyPeerWeb.SINGLETON_OBJECT_ID);
		HyPeerWebProxy hp = new HyPeerWebProxy(hwID);
		setHyPeerWeb(hp);
		
		getHyPeerWeb().addGUI(facade);
	}
}
